/**
 * 
 */
package edu.jhu.tcj.purfuit.utils;

import java.awt.Color;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import javax.swing.JFileChooser;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import edu.jhu.tcj.purfuit.Board;
import edu.jhu.tcj.purfuit.Category;
import edu.jhu.tcj.purfuit.CategoryManager;
import edu.jhu.tcj.purfuit.Game;
import edu.jhu.tcj.purfuit.Player;
import edu.jhu.tcj.purfuit.Question;
import edu.jhu.tcj.purfuit.QuestionFactory;
import edu.jhu.tcj.purfuit.Space;
import edu.jhu.tcj.purfuit.Turn;
import edu.jhu.tcj.purfuit.Turn.TurnState;

/**
 * @author Bobby
 *
 */
public class GameFile {
	
	public void saveGame(Game game) throws FileNotFoundException, IOException{
		//Serialize the game object for future loading
		List<Player> players = game.getPlayers();
		Turn turn = game.getTurn();
		Collection<Space> availSpaces = turn.getAvailableSpaces();
		StringBuffer buf = new StringBuffer();
		
		Calendar now = Calendar.getInstance();
		String timestamp = "" + now.getTimeInMillis();
		
		QuestionFactory qf = QuestionFactory.getInstance();
		List<String> usedQuesList = qf.getUsedQuestionIDs();
		//serialize the turn
		buf.append("<game>\n");
		buf.append("  <timestamp>" + timestamp + "</timestamp>\n");
		buf.append("  <id>" + game.getGameID() + "</id>\n");
		buf.append("  <usedques>");
		if(usedQuesList != null){
            for(String ques: usedQuesList){
            	buf.append(ques + ",");
            }
		}
		else buf.append("none");
		buf.append("</usedques>\n");
		buf.append("  <turn>\n");
		buf.append("    <state>" + turn.getTurnState() + "</state>\n");
		buf.append("    <player>" + turn.getPlayer().getName() + "</player>\n");
		if(turn.getCurrentQuestion() != null){
			buf.append("    <question>" + turn.getCurrentQuestion().getID() + "</question>\n");
		}
		else{
			buf.append("    <question>none</question>\n");
		}
		buf.append("    <availmoves>");
		if(turn.getAvailableSpaces() != null){
			for(Space space: turn.getAvailableSpaces()){
				buf.append(this.getSpaceID(space, game.getBoard()));
				buf.append(",");
			}
		}
		else{
			buf.append("none");
		}
		buf.append("</availmoves>\n");
		buf.append("  </turn>\n");
		
		//Serialize the players in the game
		buf.append("  <players>\n");
		for(Player player: players){
			Category[] categories = player.getCompletedCategories();
			buf.append("    <player>\n");
			buf.append("      <name>" + player.getName() + "</name>\n");
			buf.append("      <color>");
			buf.append(player.getColor().getRed() + ",");
			buf.append(player.getColor().getGreen() + ",");
			buf.append(player.getColor().getBlue());
			buf.append("</color>\n");
			buf.append("      <compcategories>");
			if(categories == null || categories.length < 1){
				buf.append("none");
			}
			else{
				for(Category category: categories){
					buf.append(category.getID() + ",");
				}
			}
			buf.append("</compcategories>\n");
			buf.append("      <space>" + this.getSpaceID(player.getSpace(), game.getBoard()));
			buf.append("</space>\n");
			buf.append("    </player>\n");
		}
		buf.append("  </players>\n");
		buf.append("</game>\n");
		
		//write the game to file
		JFileChooser fileChooser = new JFileChooser();
		int returnVal = fileChooser.showSaveDialog(null);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            File file = fileChooser.getSelectedFile();
            //This is where a real application would save the file.
            System.out.println("Saving: " + file.getName() + ".");
            fileChooser.setVisible(false);
    	    FileWriter fstream = new FileWriter(file);
    	    BufferedWriter out = new BufferedWriter(fstream);
    	    out.write(buf.toString());
    	    out.close();
        } else {
        	System.out.println("Save command cancelled by user.");
        }
	}
	
	public String getSpaceID(Space space, Board board){
		Space[][] edges = board.getEdges();
		Space[][] spokes = board.getSpokes();
		Space center = board.getCenterSpace();
		
		if(space.equals(center)){
			return "CS";
		}
		
		for(int i = 0; i < edges.length; i++){
			Space[] edge = edges[i];
			for(int j = 0; j < edge.length; j++){
				if(edge[j].equals(space)){
					return "E" + i + "" + j;
				}
			}
		}
		
		for(int k = 0; k < spokes.length; k++){
			Space[] spoke = spokes[k];
			for(int l = 0; l < spoke.length; l++){
				if(spoke[l].equals(space)){
					return "S" + k + "" + l;
				}
			}
		}
		
		return null;
	}
	
	public Game loadGame(String filename){
		Category[] categories = null;
		categories = CategoryManager.getInstance().getCategories();
		
		File file = new File(filename);
		Document doc = null;
		try {
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			doc = db.parse(file);
		} catch (Exception e){
			e.printStackTrace();
		}
		
		//get the root element
		Element docEle = doc.getDocumentElement();
		
		//Get the players from the file
		Player[] players = this.getPlayersFromDoc(docEle, categories);
		
		//create the new game
		Game game = new Game(players, categories);
		
		//Set the spaces for the players
		game.setPlayers(this.setPlayerSpaces(docEle, game));
		
		//Get the Turn object for the game
		Turn turn = this.getTurn(docEle, game);
		
		//Set the games turn object to the newly loaded one
		game.setTurn(turn);
		
		//Get the game ID
		NodeList nl = docEle.getElementsByTagName("id");
		Element id = (Element)nl.item(0);
		game.setGameID(Integer.parseInt(id.getTextContent()));
		
		//Get the game ID
		NodeList quesList = docEle.getElementsByTagName("usedques");
		Element quesid = (Element)quesList.item(0);
		String quesIDs = quesid.getTextContent();
		
		Category[] cats = null;
		try{
			cats = CategoryManager.getInstance().getCategories();
		}catch(Exception e){
			e.printStackTrace();
		}
		
		QuestionFactory factory = QuestionFactory.getInstance(new File("conf/Questions"));
		factory.loadUsedQuestions(quesIDs);
		
		return game;
		
	}
	
	private Turn getTurn(Element docEle, Game game){
		NodeList turnList = docEle.getElementsByTagName("turn");
		Element turnEle = (Element)turnList.item(0);
		NodeList nameList = turnEle.getElementsByTagName("state");
		Element state = (Element)nameList.item(0);
		String stateText = state.getTextContent();
		
		NodeList playerList = turnEle.getElementsByTagName("player");
		Element player = (Element)playerList.item(0);
		String playerText = player.getTextContent();
		
		NodeList questionList = turnEle.getElementsByTagName("question");
		Element question = (Element)questionList.item(0);
		String questionText = question.getTextContent();
		
		NodeList availList = turnEle.getElementsByTagName("availmoves");
		Element moves = (Element)availList.item(0);
		String movesText = moves.getTextContent();
		
		ArrayList<Space> availSpaces = new ArrayList<Space>();
		if(!movesText.equals("none")){
			StringTokenizer str = new StringTokenizer(movesText, ",");
		     while (str.hasMoreTokens()) {
		         String spID = str.nextToken();
		         availSpaces.add(this.getSpaceFromID(spID, game));
		     }
		}
		
		List<Player> gamePlayers = game.getPlayers();
		Player turnPlayer = null;
		for(Player pl: gamePlayers){
			if(pl.getName().equals(playerText)){
				turnPlayer = pl;
			}
		}
		
		Question turnQues = null;
		if(questionText != null && !questionText.equals("none")){
			QuestionFactory qf = QuestionFactory.getInstance();
			Map<Category, List<Question>> quesMap = qf.getAllQuestions();
			ArrayList<Question> quesList = new ArrayList<Question>();
			for(Map.Entry<Category, List<Question>> entry: quesMap.entrySet()){
				quesList.addAll(entry.getValue());
			}
			
			int quesID = Integer.parseInt(questionText);
			for(Question ques: quesList){
				if(ques.getID() == quesID){
					turnQues = ques;
				}
			}
		}
		
		TurnState tState = null;
		if(stateText.equals("WaitingToRoll")){
			tState = TurnState.WaitingToRoll;
		}
		else if(stateText.equals("WaitingToChooseSpace")){
			tState = TurnState.WaitingToChooseSpace;
		}
		else if(stateText.equals("WaitingToAnswerQuestion")){
			tState = TurnState.WaitingToAnswerQuestion;
		}
		else if(stateText.equals("TurnOver")){
			tState = TurnState.TurnOver;
		}
		
		Turn gameTurn = game.getTurn();
		gameTurn.setAfterLoad(turnPlayer, availSpaces, turnQues, tState);
		return gameTurn;
	}
	
	private Space getSpaceFromID(String id, Game game){
		char[] cSpace = id.toCharArray();
		if(cSpace[0] == 'E'){
			int c1 = Integer.parseInt("" + cSpace[1]);
			int c2 = Integer.parseInt("" + cSpace[2]);
			
			Space[][] edges = game.getBoard().getEdges();
			Space foundSpace = edges[c1][c2];
			return foundSpace;
		}
		else if((cSpace[0] == 'S')){
			int c1 = Integer.parseInt("" + cSpace[1]);
			int c2 = Integer.parseInt("" + cSpace[2]);
			
			Space[][] spokes = game.getBoard().getSpokes();
			Space foundSpace = spokes[c1][c2];
			return foundSpace;
		}
		else if(id.equals("CS")){
			Space foundSpace = game.getBoard().getCenterSpace();
			return foundSpace;
		}
		return null;
	}
	
	private List<Player> setPlayerSpaces(Element docEle, Game game){
		List<Player> gamePlayers = game.getPlayers();
		//get the players
		NodeList playersList = docEle.getElementsByTagName("players");
		Element playersEle = (Element)playersList.item(0);
		NodeList playerList = playersEle.getElementsByTagName("player");
		for(int i = 0; i < playerList.getLength(); i++){
			Element playerEle = (Element)playerList.item(i);
			NodeList nameList = playerEle.getElementsByTagName("name");
			Element playerName = (Element)nameList.item(0);
			String pName = playerName.getTextContent();
			
			NodeList spaceList = playerEle.getElementsByTagName("space");
			Element playerSpace = (Element)spaceList.item(0);
			String pSpace = playerSpace.getTextContent();
			for(Player gPlayer: gamePlayers){
				if(gPlayer.getName().equals(pName)){
					gPlayer.setSpace(this.getSpaceFromID(pSpace, game));
				}
			}
		}
		
		return gamePlayers;
	}
		
	private Player[] getPlayersFromDoc(Element docEle, Category[] categories){
		//get the players
		NodeList playersList = docEle.getElementsByTagName("players");
		Element playersEle = (Element)playersList.item(0);
		NodeList playerList = playersEle.getElementsByTagName("player");
		Player[] players = new Player[playerList.getLength()];
		for(int i = 0; i < playerList.getLength(); i++){
			String pName;
			Color pColor;
			Element playerEle = (Element)playerList.item(i);
			NodeList nameList = playerEle.getElementsByTagName("name");
			Element playerName = (Element)nameList.item(0);
			pName = playerName.getTextContent();
			
			NodeList colorList = playerEle.getElementsByTagName("color");
			Element playerColor = (Element)colorList.item(0);
			String colorString = playerColor.getTextContent();
			StringTokenizer st = new StringTokenizer(colorString, ",");
			int red = Integer.parseInt(st.nextToken());
			int green = Integer.parseInt(st.nextToken());
			int blue = Integer.parseInt(st.nextToken());
			pColor = new Color(red,green,blue);
			
			players[i] = new Player(pName, pColor);
			
			NodeList categoryList = playerEle.getElementsByTagName("compcategories");
			Element playerCat = (Element)categoryList.item(0);
			String catString = playerCat.getTextContent();
			if(!catString.equals("none")){
				StringTokenizer str = new StringTokenizer(catString, ",");
			     while (str.hasMoreTokens()) {
			         int cat = Integer.parseInt(str.nextToken());
			         for(Category category: categories){
			        	 if(category.getID() == cat){
			        		 players[i].addCompletedCategories(category);
			        	 }
			         }
			     }
			}
			
			players[i].setSpace(null);
		}
		
		return players;
	}
	
	public static void main(String[] args) {
		Player p1 = new Player("Bobby", Color.BLUE);
		p1.setSpace(null);
		
		Player p2 = new Player("Brad", Color.BLACK);
		p2.setSpace(null);
		
		Player p3 = new Player("Richard", Color.GREEN);
		p3.setSpace(null);
		
		Player p4 = new Player("Sam", Color.RED);
		p4.setSpace(null);
		
		Player[] players = new Player[4];
		players[0] = p1;
		players[1] = p2;
		players[2] = p3;
		players[3] = p4;
		
		/**Category cat1 = new Category();
		cat1.setName("People");
		cat1.setColor(new Color(255,255,255));
		Category cat2 = new Category();
		cat2.setName("Places");
		cat2.setColor(new Color(0,0,255));
		Category cat3 = new Category();
		cat3.setName("Events");
		cat3.setColor(new Color(0,255,0));
		Category cat4 = new Category();
		cat4.setName("Holiday");
		cat4.setColor(new Color(255,0,0));
		
		Category[] cats = new Category[4];
		cats[0] = cat1;
		cats[1] = cat2;
		cats[2] = cat3;
		cats[3] = cat4;**/
		
		//Category[] cats = null;
		//try{
		//	cats = CategoryManager.getInstance().getCategories();
		//}catch(Exception e){
		//	e.printStackTrace();
		//}
		
		//Game game = new Game(players, cats);
		//QuestionFactory factory = QuestionFactory.getInstance(new File("conf/Questions"));
		//Question random = factory.generateQuestion(cats[0]);
		//Question random2 = factory.generateQuestion(cats[1]);
		
		GameFile gf = new GameFile();
		//try{
		//    gf.saveGame(game);
		//}
		//catch(Exception e){
		//	e.printStackTrace();
		//}
		Game gameLoaded = gf.loadGame("conf/gamedata/1314030094341.xml");
		Turn gameTurn = gameLoaded.getTurn();
		System.out.println("Game ID: " + gameLoaded.getGameID());
		System.out.println("Used List: " + QuestionFactory.getInstance().getUsedQuestionIDs());
		System.out.println("Turn-State: " + gameTurn.getTurnState());
		System.out.println("Turn-Player: " + gameTurn.getPlayer().getName());
		System.out.println("Turn-Question: " + gameTurn.getCurrentQuestion());
		System.out.println("Turn-Moves: " + gameTurn.getAvailableSpaces());
		
		List<Player> loadplayers = gameLoaded.getPlayers();
		for(Player loadplayer: loadplayers){
			System.out.println("Player-Name: " + loadplayer.getName());
			System.out.println("Player-Color: " + loadplayer.getColor());
			System.out.println("Player-Space: " + loadplayer.getSpace());
			Category[] plCats = loadplayer.getCompletedCategories();
			for(int i = 0; i<plCats.length; i++){
				System.out.println("Player-Compcat: " + plCats[i].getName());
			}
			
		}
	}
}
